// 导入查找表
import { FixedMathLut } from './FixedMathLut';

export namespace FixedMath {
    
    // ts的number类型是64位，所以需要使用位运算来模拟定点数
    export const FIXED_PRECISION = 16;
    export const SCALE_FACTOR = 1 << FIXED_PRECISION;
    export const INV_SCALE_FACTOR = 1 / SCALE_FACTOR;
    export const MAX_VALUE = 1 << 32 - 1;
    export const MIN_VALUE = -(1 << 32);

    declare const fixed: unique symbol;
    type fixed = number & { [fixed]: true };

    // 常量定义 - 直接使用预计算的值
    export const ZERO = FixedMathLut.CONSTANTS.ZERO as fixed;
    export const ONE = FixedMathLut.CONSTANTS.ONE as fixed;
    export const HALF = FixedMathLut.CONSTANTS.HALF as fixed;
    export const PI = FixedMathLut.CONSTANTS.PI as fixed;
    export const TWO_PI = FixedMathLut.CONSTANTS.TWO_PI as fixed;
    export const HALF_PI = FixedMathLut.CONSTANTS.HALF_PI as fixed;
    export const NEG_PI = FixedMathLut.CONSTANTS.NEG_PI as fixed;
    export const NEG_HALF_PI = FixedMathLut.CONSTANTS.NEG_HALF_PI as fixed;
    export const E = FixedMathLut.CONSTANTS.E as fixed;

    // 三角函数查表 - 预先计算好的查找表
    const SIN_TABLE_SIZE = 360;
    const SIN_TABLE: fixed[] = FixedMathLut.SIN_TABLE.map(val => val as fixed);
    const TAN_TABLE: fixed[] = FixedMathLut.TAN_TABLE.map(val => val as fixed);
    const ASIN_TABLE_SIZE = 200;
    const ASIN_TABLE: fixed[] = FixedMathLut.ASIN_TABLE.map(val => val as fixed);
    const ACOS_TABLE: fixed[] = FixedMathLut.ACOS_TABLE.map(val => val as fixed);
    const DEGREES_TO_RADIANS = div(PI, fromInt(180));
    const RADIANS_TO_DEGREES = div(fromInt(180), PI);

    /**
     * 将整数转换为定点数
     * @param value 整数
     * @returns 定点数
     */
    export function fromInt(value: number): fixed {
        return (value << FIXED_PRECISION) as fixed;
    }

    /**
     * 将浮点数转换为定点数
     * @param value 浮点数
     * @returns 定点数
     */
    export function fromFloat(value: number): fixed {
        // 使用更确定性的舍入方法
        return Math.floor(value * SCALE_FACTOR + 0.5) as fixed;
    }

    /**
     * 将定点数转换为浮点数
     * @param value 定点数
     * @returns 浮点数
     */
    export function toFloat(value: fixed): number {
        return value * INV_SCALE_FACTOR;
    }

    export function toString(value: fixed): string {
        return toFloat(value).toFixed(4);
    }

    /**
     * 加法 
     * @param a 
     * @param b 
     * @returns 
     */
    export function add(a: fixed, b: fixed): fixed {
        return (a + b) as fixed;
    }

    /**
     * 减法
     * @param a 
     * @param b 
     * @returns 
     */
    export function sub(a: fixed, b: fixed): fixed {
        return (a - b) as fixed;
    }

    /**
     * 乘法
     * @param a 
     * @param b 
     * @returns 
     */
    export function mul(a: fixed, b: fixed): fixed {
        // 使用Math.imul提高精度和跨平台一致性
        const highBits = Math.imul(a >> 8, b >> 8);
        const lowBits = Math.imul(a & 0xFF, b & 0xFF) >> 16;
        return ((highBits << 8) + lowBits) as fixed;
    }

    /**
     * 除法
     * @param a 
     * @param b 
     * @returns 
     */
    export function div(a: fixed, b: fixed): fixed {
        // 扩大除数来保持精度，避免使用浮点数
        return Math.floor(((a << FIXED_PRECISION) / b) + 0.5) as fixed;
    }

    /**
     * 求余
     * @param a 
     * @param b 
     * @returns 
     */
    export function mod(a: fixed, b: fixed): fixed {
        return (a % b) as fixed;
    }

    export function clamp(value: fixed, min: fixed, max: fixed): fixed {
        if (value < min) {
            return min;
        }
        if (value > max) {
            return max;
        }
        return value;
    }

    /**
     * 线性插值
     * @param a 
     * @param b 
     * @param t 
     * @returns 
     */ 
    export function lerp(a: fixed, b: fixed, t: fixed): fixed {
        return add(a, mul(sub(b, a), t));
    }
    
    /**
     * 开平方 - 使用牛顿迭代法实现
     * @param value 
     * @returns 
     */
    export function sqrt(value: fixed): fixed {
        if (value <= 0) return 0 as fixed;
        
        // 设置初始估计值
        let guess = ONE;
        let lastGuess = ZERO;
        
        // 牛顿迭代
        for (let i = 0; i < 8 && guess !== lastGuess; i++) {
            lastGuess = guess;
            // 牛顿迭代公式: x_next = (x + n/x) / 2
            guess = div(add(guess, div(value, guess)), fromInt(2));
        }
        
        return guess;
    }

     /**  
     * 整数幂运算 - 使用平方乘法算法
     * @param base 
     * @param exponent 必须是整数
     * @returns 
     */
    export function powi(base: fixed, exponent: number): fixed {
        if (exponent === 0) return ONE;
        if (base === 0) return ZERO;
        
        let result = ONE;
        let power = base;
        let exp = Math.abs(exponent);
        
        // 平方乘法算法
        while (exp > 0) {
            if (exp & 1) { // 二进制最低位为1
                result = mul(result, power);
            }
            power = mul(power, power);
            exp >>= 1; // 右移一位
        }
        
        return exponent < 0 ? div(ONE, result) : result;
    }

    /**
     * 幂运算 - 对于小数指数，使用对数近似
     * @param base 
     * @param exponent 
     * @returns 
     */
    export function pow(base: fixed, exponent: fixed): fixed {
        // 对于整数指数，使用更快的powi
        const expFloat = toFloat(exponent);
        if (Number.isInteger(expFloat)) {
            return powi(base, expFloat);
        }
        
        // 对于非整数指数，使用exp(log(base) * exponent)
        return exp(mul(log(base), exponent));
    }

    /**
     * 绝对值
     * @param value 
     * @returns 
     */
    export function abs(value: fixed): fixed {
        return (value < 0 ? -value : value) as fixed;
    }

    /**
     * 符号
     * @param value 
     * @returns 1 if positive, -1 if negative, 0 if zero
     */
    export function sign(value: fixed): fixed {
        if (value > 0) return ONE;
        if (value < 0) return fromInt(-1);
        return ZERO;
    }

    /**
     * 向下取整
     * @param value 
     * @returns 
     */
    export function floor(value: fixed): fixed {
        return ((value >> FIXED_PRECISION) << FIXED_PRECISION) as fixed;
    }

    /**
     * 向上取整
     * @param value 
     * @returns 
     */
    export function ceil(value: fixed): fixed {
        const floorVal = floor(value);
        return (value > floorVal) ? add(floorVal, ONE) : value;
    }

    /**
     * 四舍五入
     * @param value 
     * @returns 
     */
    export function round(value: fixed): fixed {
        return floor(add(value, HALF));
    }

    /**
     * 角度转弧度
     * @param degrees 角度值
     * @returns 弧度值
     */
    export function toRadians(degrees: fixed): fixed {
        return mul(degrees, DEGREES_TO_RADIANS);
    }

    /**
     * 弧度转角度
     * @param radians 弧度值
     * @returns 角度值
     */
    export function toDegrees(radians: fixed): fixed {
        return mul(radians, RADIANS_TO_DEGREES);
    }

    /**
     * 正弦函数 - 使用原生Math.sin并转换为定点数
     * @param angle 角度（弧度）
     * @returns 
     */
    export function sin(angle: fixed): fixed {
        return fromFloat(Math.sin(toFloat(angle)));
    }

    /**
     * 余弦函数 - 使用原生Math.cos并转换为定点数
     * @param angle 角度（弧度）
     * @returns 
     */
    export function cos(angle: fixed): fixed {
        return fromFloat(Math.cos(toFloat(angle)));
    }

    /**
     * 正切函数 - 使用原生Math.tan并转换为定点数
     * @param angle 角度（弧度）
     * @returns 
     */
    export function tan(angle: fixed): fixed {
        return fromFloat(Math.tan(toFloat(angle)));
    }

    /**
     * 反正弦函数 - 使用原生Math.asin并转换为定点数
     * @param value [-1, 1]范围内的值
     * @returns 弧度值
     */
    export function asin(value: fixed): fixed {
        // 限制输入在有效范围内
        value = clamp(value, fromInt(-1), ONE);
        return fromFloat(Math.asin(toFloat(value)));
    }

    /**
     * 反余弦函数 - 使用原生Math.acos并转换为定点数
     * @param value [-1, 1]范围内的值
     * @returns 弧度值
     */
    export function acos(value: fixed): fixed {
        // 限制输入在有效范围内
        value = clamp(value, fromInt(-1), ONE);
        return fromFloat(Math.acos(toFloat(value)));
    }

    /**
     * 通过点乘计算两个向量之间的角度
     * 针对点乘场景优化的角度计算
     * @param dotProduct 两个单位向量的点乘结果
     * @returns 弧度值
     */
    export function angleFromDot(dotProduct: fixed): fixed {
        // 对于几乎相同方向的向量，返回0
        if (approximately(dotProduct, ONE, fromFloat(0.001))) {
            return ZERO;
        }
        
        // 对于几乎相反方向的向量，返回π
        if (approximately(dotProduct, fromInt(-1), fromFloat(0.001))) {
            return PI;
        }
        
        // 使用更快的直接查表
        return acos(dotProduct);
    }

    /**
     * 通过两个向量计算角度 (更高效的实现)
     * @param x1 第一个向量的x分量
     * @param y1 第一个向量的y分量
     * @param x2 第二个向量的x分量
     * @param y2 第二个向量的y分量
     * @returns 弧度角度值
     */
    export function angleBetweenVectors(x1: fixed, y1: fixed, x2: fixed, y2: fixed): fixed {
        // 计算向量长度
        const len1 = sqrt(add(mul(x1, x1), mul(y1, y1)));
        const len2 = sqrt(add(mul(x2, x2), mul(y2, y2)));
        
        // 避免除零错误
        if (len1 === 0 || len2 === 0) {
            return ZERO;
        }
        
        // 计算点积并归一化
        const dotProd = add(mul(x1, x2), mul(y1, y2));
        const normalizedDot = div(dotProd, mul(len1, len2));
        
        // 使用优化的角度计算函数
        return angleFromDot(normalizedDot);
    }

    /**
     * 反正切函数 - 使用原生Math.atan并转换为定点数
     * @param value 
     * @returns 
     */
    export function atan(value: fixed): fixed {
        return fromFloat(Math.atan(toFloat(value)));
    }

    /**
     * 反正切函数（两参数版本）- 使用原生Math.atan2并转换为定点数
     * @param y 
     * @param x 
     * @returns 
     */
    export function atan2(y: fixed, x: fixed): fixed {
        return fromFloat(Math.atan2(toFloat(y), toFloat(x)));
    }

    /**
     * 取反操作
     * @param value 
     * @returns 
     */
    export function neg(value: fixed): fixed {
        return (0 - value) as fixed;
    }

    /**
     * 最小值
     * @param a 
     * @param b 
     * @returns 
     */
    export function min(a: fixed, b: fixed): fixed {
        return (a < b ? a : b) as fixed;
    }

    /**
     * 最大值
     * @param a 
     * @param b 
     * @returns 
     */
    export function max(a: fixed, b: fixed): fixed {
        return (a > b ? a : b) as fixed;
    }

    /**
     * 自然对数 - 使用泰勒级数近似
     * @param value 
     * @returns 
     */
    export function log(value: fixed): fixed {
        if (value <= 0) {
            return fromInt(-1000); // 返回一个非常小的值作为错误标记
        }
        
        // 对于大值，使用log(a*b) = log(a) + log(b)，将值缩小到[0.5, 2]范围
        let result = ZERO;
        let x = value;
        
        // 处理大值
        while (x >= fromInt(2)) {
            x = div(x, E);
            result = add(result, ONE);
        }
        
        // 处理小值
        while (x < HALF) {
            x = mul(x, E);
            result = sub(result, ONE);
        }
        
        // 现在x在[0.5, 2]范围，使用泰勒级数
        // log(1+y) = y - y^2/2 + y^3/3 - ...
        const y = sub(x, ONE);
        const y2 = mul(y, y);
        const y3 = mul(y, y2);
        const y4 = mul(y, y3);
        const y5 = mul(y, y4);
        
        const term1 = y;
        const term2 = div(y2, fromInt(2));
        const term3 = div(y3, fromInt(3));
        const term4 = div(y4, fromInt(4));
        const term5 = div(y5, fromInt(5));
        
        return add(result, add(sub(add(sub(term1, term2), term3), term4), term5));
    }

    /**
     * 以10为底的对数
     * @param value 
     * @returns 
     */
    export function log10(value: fixed): fixed {
        // log10(x) = log(x) / log(10)
        return div(log(value), fromFloat(2.302585092994046)); // log(10)
    }

    /**
     * 指数函数 - 使用泰勒级数近似
     * @param value 
     * @returns 
     */
    export function exp(value: fixed): fixed {
        // 处理溢出
        if (value >= fromInt(11)) return fromInt(1000000);
        if (value <= fromInt(-11)) return ZERO;
        
        // 使用整数部分+小数部分的方式计算
        // exp(a+b) = exp(a) * exp(b)
        const intPart = floor(value);
        const fracPart = sub(value, intPart);
        
        // 计算整数部分：exp(n)
        const intExp = powi(E, toFloat(intPart));
        
        // 计算小数部分：使用泰勒级数
        // exp(x) = 1 + x + x^2/2! + x^3/3! + ...
        const x2 = mul(fracPart, fracPart);
        const x3 = mul(x2, fracPart);
        const x4 = mul(x3, fracPart);
        const x5 = mul(x4, fracPart);
        
        const term1 = ONE;
        const term2 = fracPart;
        const term3 = div(x2, fromInt(2));
        const term4 = div(x3, fromInt(6));
        const term5 = div(x4, fromInt(24));
        const term6 = div(x5, fromInt(120));
        
        const fracExp = add(add(add(add(add(term1, term2), term3), term4), term5), term6);
        
        return mul(intExp, fracExp);
    }

    /**
     * 比较两个定点数是否近似相等
     * @param a 
     * @param b 
     * @param epsilon 精度阈值
     * @returns 
     */
    export function approximately(a: fixed, b: fixed, epsilon: fixed = fromFloat(0.0001)): boolean {
        return abs(sub(a, b)) <= epsilon;
    }

    /**
     * 生成一个介于0到1之间的伪随机数
     * 使用确定性随机数生成器，确保帧同步
     * @param seed 随机种子
     * @returns 一个确定性的伪随机数和新种子
     */
    export function random(seed: number): [fixed, number] {
        // 使用XorShift算法，比线性同余法更均匀且周期更长
        let x = seed;
        x ^= x << 13;
        x ^= x >> 17;
        x ^= x << 5;
        // 确保正值
        if (x < 0) x += 0xFFFFFFFF + 1;
        return [div(fromInt(x >>> 0), fromInt(0xFFFFFFFF)), x];
    }

    /**
     * 插值函数 - 平滑步进
     * 返回在边缘平滑的阶梯函数
     * @param edge0 第一个边缘
     * @param edge1 第二个边缘
     * @param x 输入值
     * @returns 插值结果
     */
    export function smoothstep(edge0: fixed, edge1: fixed, x: fixed): fixed {
        // 将x限制在[0,1]范围内
        x = clamp(div(sub(x, edge0), sub(edge1, edge0)), ZERO, ONE);
        // 计算多项式: 3x^2 - 2x^3
        const x2 = mul(x, x);
        const x3 = mul(x, x2);
        return add(mul(fromInt(3), x2), mul(fromInt(-2), x3));
    }
}
